// $Id$
package de.servicezombie.cxf;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.servicezombie.pub.r1.CommonRestResponse;

public class AttachRestResponseOutInterceptor extends AbstractPhaseInterceptor<Message> {
	
	private static final Logger log = LoggerFactory.getLogger(AttachRestResponseOutInterceptor.class);
	private static final String CXF_PACKAGE_PREFIX = "org.apache.cxf.jaxrs";

	private static final Set<Class<?>> wrapperBlacklist = new HashSet<Class<?>>();
	static {
		wrapperBlacklist.add(CommonRestResponse.class);
	}

	public AttachRestResponseOutInterceptor() {
		super(Phase.PRE_LOGICAL);
	}

	public void handleMessage(Message message) throws Fault {
		if (log.isDebugEnabled()) {
			log.debug("handleMessage: >> " + message);
		}

		MessageContentsList messageContentsList = MessageContentsList.getContentsList(message);
		Object data = messageContentsList.get(0);
		
		if (log.isDebugEnabled()) {
			log.debug("handleMessage: first message is " + data);
		}
		
		WebserviceTemplate template = new WebserviceTemplateFactory().build();
		CommonRestResponse<Object> wrapper = template.getWebserviceResponse();
		
		if(shouldBodyDataBeAttached(data)) {
			if (log.isDebugEnabled()) {
				log.debug("handleMessage: replace body in response message.");
			}			
			
			wrapper.setBody(data);
		}
		
		Response response = buildResponse(data, wrapper);
		if (response != null) {
			messageContentsList.set(0, response);
		}
		
		if (log.isDebugEnabled()) {
			log.debug("handleMessage: <<");
		}
	}

	private Response buildResponse(Object data, CommonRestResponse<?> wrapper) {
		
		if(data instanceof Response) {
			return (Response) data;
		}
				
		Response response = null;
		
		switch(wrapper.getSys().getReturnCode()) {
			case OK:
				response = Response.status(Status.OK).entity(wrapper).build();
				break;
		}
				
		return response;	
	}

	private boolean shouldBodyDataBeAttached(Object data) {
		if(data == null) {
			return false;
		}
		
		Class<?> clazz = data.getClass();
		boolean omitWrapper = clazz.getPackage().getName().startsWith(CXF_PACKAGE_PREFIX);
		omitWrapper = omitWrapper || data instanceof CommonRestResponse;
		return ! omitWrapper;
	}

}
